﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Engine.Sgml.Merging;

namespace Engine.Sgml.Allocation {
    internal sealed class InBlockAllocator {
        private INodeIterator descendantIterator;
        private InconsistentBlockAllocator blockAllocator;

        public InBlockAllocator(InconsistentBlockAllocator allocator) {
            Guard.ArgumentNotNull(allocator, "allocator");
            this.blockAllocator = allocator;
            this.descendantIterator = new DescendantsIterator();
            }

        public bool Allocate(InconsistentBlock block) {
            if (block.Count < 2)
                return false;
            block.Restore();
            InconsistentBlock helperBlock = new InconsistentBlock(block.Ancestor);
            for (int i = block.Count - 1; i >= 0; i--) {
                helperBlock.Add(block[i]);
                for (int j = i - 1; j >= 0; j--) {
                    SElement ancestor = block[j];
                    if (blockAllocator.CanAllocate(helperBlock, ancestor) && blockAllocator.AllocateAtBottomOfSubtree(helperBlock, ancestor))
                        break;
                    else {
                        descendantIterator.Reset(ancestor);
                        while (descendantIterator.MovePrevious()) {
                            ancestor = descendantIterator.Current;
                            if (blockAllocator.CanAllocate(helperBlock, ancestor) && blockAllocator.AllocateAtBottomOfSubtree(helperBlock, ancestor)) {
                                block.RemoveAt(i);
                                break;
                                }
                            }
                        if (helperBlock.Count == 0)
                            return true;
                        }
                    }
                helperBlock.Clear();
                }
            return block.Count == 0;
            }
        }
    }
